﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup.Primitives;
using System.Windows.Media;
using MVVMFramework.ViewModel;

namespace MVVMFramework.View
{
    /// <summary>
    /// Base implementation of Window (Base View)
    /// </summary>
    public abstract class WindowBase : Window //, IView
    {
        /// <summary>
        /// View Model for current View
        /// </summary>
        protected ViewModelBase ViewModel
        {
            get
            {
                return DataContext as ViewModelBase;
            }
        }

        protected bool HideOnClose;

        protected WindowBase()
            : this(null)
        {

        }

        protected WindowBase(ViewModelBase viewModel)
        {
            DataContextChanged += windowBase_DataContextChanged;

            DataContext = viewModel;
            Loaded += windowBase_Loaded;
            Unloaded += windowBase_Unloaded;
        }

        #region Refresh View Model Data

        public static readonly DependencyProperty RefreshLookupsOnLoadProperty =
            DependencyProperty.Register("RefreshLookupsOnLoad", typeof(bool), typeof(WindowBase), new PropertyMetadata(true));

        public bool RefreshLookupsOnLoad
        {
            get
            {
                return (bool)GetValue(RefreshLookupsOnLoadProperty);
            }
            set
            {
                SetValue(RefreshLookupsOnLoadProperty, value);
            }
        }

        public static readonly DependencyProperty RefreshLookupsWithForceProperty =
            DependencyProperty.Register("RefreshLookupsWithForce", typeof(bool), typeof(WindowBase), new PropertyMetadata(false));

        public bool RefreshLookupsWithForce
        {
            get
            {
                return (bool)GetValue(RefreshLookupsWithForceProperty);
            }
            set
            {
                SetValue(RefreshLookupsWithForceProperty, value);
            }
        }

        public static readonly DependencyProperty RefreshViewModelOnLoadProperty =
            DependencyProperty.Register("RefreshViewModelOnLoad", typeof(bool), typeof(WindowBase), new PropertyMetadata(true));

        public bool RefreshViewModelOnLoad
        {
            get
            {
                return (bool)GetValue(RefreshViewModelOnLoadProperty);
            }
            set
            {
                SetValue(RefreshViewModelOnLoadProperty, value);
            }
        }

        public static readonly DependencyProperty RefreshViewModelWithForceProperty =
            DependencyProperty.Register("RefreshViewModelWithForce", typeof(bool), typeof(WindowBase), new PropertyMetadata(false));

        public bool RefreshViewModelWithForce
        {
            get
            {
                return (bool)GetValue(RefreshViewModelWithForceProperty);
            }
            set
            {
                SetValue(RefreshViewModelWithForceProperty, value);
            }
        }

        #endregion

        /// <summary>
        /// Called when view is loaded
        /// </summary>
        protected virtual void OnViewLoaded()
        {
            if (RefreshLookupsOnLoad)
            {
                // load lookups
                if (ViewModel != null)
                    ViewModel.RefreshLookups(RefreshLookupsWithForce);
            }

            // refresh
            if (RefreshViewModelOnLoad)
            {
                IRefreshable refreshable = ViewModel as IRefreshable;
                if (refreshable != null)
                    refreshable.Refresh(RefreshViewModelWithForce);
            }
        }

        /// <summary>
        /// Called when view is unloaded
        /// </summary>
        protected virtual void OnViewUnloaded()
        {
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            if (HideOnClose)
            {
                e.Cancel = true;
                Hide();
            }
            else
            {
                if (ViewModel != null)
                    ViewModel.ViewCloseRequest -= OnViewCloseRequest;

                base.OnClosing(e);
            }
        }

        protected virtual void OnViewCloseRequest(bool? obj)
        {
            if (System.Windows.Interop.ComponentDispatcher.IsThreadModal)
            {
                if (ViewModel != null)
                    ViewModel.ViewCloseRequest -= OnViewCloseRequest;
                DialogResult = obj;
            }
            else
            {
                if (HideOnClose)
                {
                    Hide();
                }
                else
                {
                    if (ViewModel != null)
                        ViewModel.ViewCloseRequest -= OnViewCloseRequest;

                    Close();
                }
            }
        }

        #region Private Methods

        private void windowBase_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            object oldContext = e.OldValue;
            unsubscribeFromDataContextEvents(oldContext);

            object newContext = e.NewValue;
            subscribeOnDataContextEvents(newContext);
        }

        private void windowBase_Loaded(object sender, RoutedEventArgs e)
        {
            OnViewLoaded();
        }

        private void windowBase_Unloaded(object sender, RoutedEventArgs e)
        {
            OnViewUnloaded();
        }

        private void subscribeOnDataContextEvents(object dataContext)
        {
            ViewModelBase vm = dataContext as ViewModelBase;
            if (vm != null)
                vm.ViewCloseRequest += OnViewCloseRequest;

            var dataError = dataContext as INotifyDataErrorInfo;
            if (dataError != null)
                dataError.ErrorsChanged += dataContext_ErrorsChanged;
        }

        private void unsubscribeFromDataContextEvents(object dataContext)
        {
            ViewModelBase vm = dataContext as ViewModelBase;
            if (vm != null)
                vm.ViewCloseRequest -= OnViewCloseRequest;

            var dataError = dataContext as INotifyDataErrorInfo;
            if (dataError != null)
                dataError.ErrorsChanged -= dataContext_ErrorsChanged;
        }

        private void dataContext_ErrorsChanged(object sender, DataErrorsChangedEventArgs e)
        {
           
        }

        #endregion
    }
}
